using namespace std;

#include "../AnalyseurXML/gen/document.h"
#include "../AnalyseurXML/gen/node.h"
#include "../AnalyseurXML/gen/attr_node.h"
#include "../AnalyseurXML/gen/element.h"
#include "../AnalyseurXML/gen/attribute.h"
#include "../AnalyseurXML/gen/content_node.h"
#include "../AnalyseurXML/gen/spec_node.h"

#include "../AnalyseurDTD/gen/doctype_definition.h"

#include <string>
#include <cstring>
#include <cstdio>
#include <cstdlib>

#include "../AnalyseurXML/gen/commun.h"
#include "../AnalyseurXML/gen/xml.tab.h"
#include "../AnalyseurDTD/gen/dtd.tab.h"
#include "dtdvalidator.h"

#include "xsltransformer.h"

// error codes
#define RETOK 0
#define RETNOK 1
#define RETDTDERROR 10
#define RETDTDMISSING 11
#define RETXMLERROR 20
#define RETXMLFILEERROR 21
#define RETXMLPARSEERROR 22
#define RETXMLDTDINVALID 23
#define RETXMLDTDERRORS 24
#define RETXSLTERROR 30

extern FILE* xmlin;
extern int xmlparse(Document* doc);
extern FILE* dtdin;
extern int dtdparse(DoctypeDefinition* doctypeDef);

void restartXMLState();
 
int main(int argc, char **argv)
{
  int err;

  char* xmlFilePath = NULL;
  char* xsltFilePath = NULL;
  char dtdFilePath[50];

  bool verbose = false;
  bool validateDTD = false;

  for(int i = 0; i < argc; i++)
  {
	if(strcmp(argv[i], "-v") == 0)
	{
		verbose = true;
	}
	else if (strcmp(argv[i], "--validate") == 0)
	{
		validateDTD = true;
	}
	else if((strcmp(argv[i], "--xslt") == 0) && (i < argc-2)) // next arguments are the xslt file and the xml file
	{
		xsltFilePath = argv[i+1];
	}
  }

  if(argc > 1)
  {
	xmlFilePath = argv[argc-1];
  }
  
  if((xmlFilePath != NULL) && (strcmp(xmlFilePath, "") != 0))
  {
	FILE* fid = fopen(xmlFilePath, "r");
	if(fid) // file open correctly
	{

	 // xmldebug = 1; // pour enlever l'affichage de l'éxécution du parser, commenter cette ligne

	  Document* doc = new Document;

	  xmlin = fid;

	  err = xmlparse(doc);

	fclose(fid);

	  if (err == 0)
	  {
		printf("XML File '%s' has been parsed with success.\n", xmlFilePath);

		strcpy(dtdFilePath, doc->getNsFile().c_str());

	  	if(verbose)
		{
			doc->print(cout);
		}


		if(validateDTD)
		{
			printf("Validating XML document with DTD...\n");
			if(strcmp(dtdFilePath, "") != 0)
			{
				FILE* dtdfid = fopen(dtdFilePath, "r");
				if (dtdfid)
				{
					dtdin = dtdfid;
					DoctypeDefinition* doctypeDef = new DoctypeDefinition();
					int dtderr;
					dtderr = dtdparse(doctypeDef);
					fclose(dtdfid);
					if (dtderr == 0)
					{
						printf("DTD File '%s' has been parsed with success.\n", dtdFilePath);
						if (validateDtd(doctypeDef, doc))
						{
							printf("XML File has been validated with success\n");
						}
						else
						{
							printf("XML File is not DTD-valid\n");
							return RETXMLDTDINVALID;
						}
					}
					else
					{
						printf("DTD File '%s' hase been parsed with %d errors\n", dtdFilePath, dtderr);
						return RETXMLDTDERRORS;
					}
				}
				else
				{
					printf("error : cannot open DTD file\n");
				}
			}
			else
			{
				printf("Error : DTD file is not specified in the XML file\n");
				return RETDTDMISSING;
			}
		}

		if(xsltFilePath != NULL)
		{
			printf("Transforming XML document using XSLT...\n");
			
			FILE* xslt_fid = fopen(xsltFilePath, "r");
			if(xslt_fid)
			{
				Document* xslDoc = new Document;
				xmlin = xslt_fid;

				restartXMLState();
				err = xmlparse(xslDoc);

				if(err == 0)
				{
					printf("Starting transformation...\n");
					XSLTransformer xslTransformer(xslDoc);
					Document* newXml = xslTransformer.transformXML(doc);
					if(newXml != NULL)
					{
						newXml->print(cout);
					}
					else
					{
						printf("Error : cannot create the new XML document\n");
	  					return RETXSLTERROR;
					}
		
				}
	  			else
	  			{
	  				printf("Error : cannot parse the xslt file '%s' (parser returned %d error(s))\n", xsltFilePath, err);
	  				return RETXSLTERROR;
	  			}
					

				fclose(xslt_fid);
			}
			else
			{
				printf("Error : cannot open XSLT file\n");
				return RETXSLTERROR;
			}
		}


	  }
	  else
	  {
			printf("Error : cannot parse the xml file (parser returned %d error(s))\n", err);
			return RETXMLPARSEERROR;
		}


	}
	else
	{
		printf("Error opening '%s'\n", xmlFilePath);
		return RETXMLFILEERROR;
	}




  }
  else
	printf("Usage is : final [-v] [--validate]  [--xslt xslt_file] xml_file\n");

  return RETOK;
}

